module spi_ctrl #(parameter WR_LENTH = 3)(
    input                   clk         ,
    input                   rst_n       ,
    input         [2:0]     key_down    ,
    input         [7:0]     rd_data     ,
    input                   trans_done  ,
    input         [7:0]     rx_data     ,
    input                   rx_vld      ,
    output  reg             rw_flag     ,
    output  reg   [23:0]    out_data    ,
    output  reg             data_vld    ,
    output  reg   [7:0]     wr_data     
);

wire            rw_flag_id;
wire    [23:0]  addr_data;
wire            id_vld;
wire    [7:0]   wr_data_id;

wire            rw_flag_rd;
wire    [23:0]  rd_data_r;
wire            rddata_vld;
wire    [7:0]   wr_data_rd;

wire            rw_flag_wr;
wire    [7:0]   wr_data_wr;

wire    [5:0]   usedw     ;
wire            skipidle  ;

//状态机
reg     [1:0]   state_c ;
reg     [1:0]   state_n ;

localparam  IDLE    = 2'd0,
            RD_ID   = 2'd1,
            RD_DATAS= 2'd2,
            WR_DATAS= 2'd3;

wire        IDLE_2_RDID;
wire        IDLE_2_RDATA;
wire        IDLE_2_WDATA;
wire        RDID_2_IDLE;
wire        RDATA_2_IDLE;
wire        WDATA_2_IDLE;

//第一段：同步时序描述状态转移
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        state_c <= IDLE;
    end 
    else begin 
        state_c <= state_n;
    end 
end
    
//第二段：组合逻辑判断状态转移条件，描述状态转移规律
always @(*) begin
    case(state_c)
        IDLE        : begin
            if(IDLE_2_RDID)
                state_n = RD_ID;
            else if(IDLE_2_RDATA)
                state_n = RD_DATAS;
            else if(IDLE_2_WDATA)
                state_n = WR_DATAS;
            else
                state_n = state_c;
        end
        RD_ID       : state_n = (RDID_2_IDLE)  ?  IDLE : state_c;
        RD_DATAS    : state_n = (RDATA_2_IDLE) ?  IDLE : state_c;
        WR_DATAS    : state_n = (WDATA_2_IDLE) ?  IDLE : state_c;
        default : state_n = state_c ;
    endcase
end

assign      IDLE_2_RDID     = (state_c == IDLE)     && key_down[0];
assign      IDLE_2_RDATA    = (state_c == IDLE)     && key_down[1];
assign      IDLE_2_WDATA    = (state_c == IDLE)     && (key_down[2] || usedw >= WR_LENTH);
assign      RDID_2_IDLE     = (state_c == RD_ID)    && id_vld;
assign      RDATA_2_IDLE    = (state_c == RD_DATAS) && rddata_vld;
assign      WDATA_2_IDLE    = (state_c == WR_DATAS) && skipidle;

//第三段：rw_flag  out_data  data_vld  wr_data 数据描述
always @(posedge clk or negedge rst_n)begin 
    if(!rst_n)begin
        rw_flag    <=   1'b0;
        out_data   <=   'd0;
        data_vld   <=   1'b0;
        wr_data    <=   'd0;
    end 
    else if(state_c == IDLE)begin
        rw_flag    <=   1'b0 ;
        out_data   <=   out_data;
        data_vld   <=   1'b0;
        wr_data    <=   wr_data ;
    end
    else if(state_c == RD_ID)begin 
        rw_flag    <=   rw_flag_id;
        out_data   <=   addr_data;
        data_vld   <=   id_vld;
        wr_data    <=   wr_data_id;
    end 
    else if(state_c == RD_DATAS)begin
        rw_flag    <=   rw_flag_rd;
        out_data   <=   rd_data_r;
        data_vld   <=   rddata_vld;
        wr_data    <=   wr_data_rd;
    end
    else if(state_c == WR_DATAS)begin
        rw_flag    <=   rw_flag_wr;
        out_data   <=   out_data;
        data_vld   <=   data_vld;
        wr_data    <=   wr_data_wr;
    end
    else begin 
        rw_flag    <=   rw_flag ;
        out_data   <=   out_data;
        data_vld   <=   data_vld;
        wr_data    <=   wr_data ;
    end 
end

rd_id   inst_rd_id(
    .clk        (clk            ),
    .rst_n      (rst_n          ),
    .key_down   (key_down       ),
    .rd_data    (rd_data        ),
    .trans_done (trans_done     ),
    .rw_flag    (rw_flag_id     ),
    .addr_data  (addr_data      ),
    .data_vld   (id_vld         ),
    .wr_data    (wr_data_id     )
);

rd_datas inst_rd_datas(
    .clk        (clk            ),
    .rst_n      (rst_n          ),
    .key_down   (key_down       ),
    .rd_data    (rd_data        ),
    .trans_done (trans_done     ),
    .rw_flag    (rw_flag_rd     ),
    .rd_data_r  (rd_data_r      ),
    .data_vld   (rddata_vld     ),
    .wr_data    (wr_data_rd     )
);

wr_datas    inst_wr_datas(
    .clk       (clk       ),
    .rst_n     (rst_n     ),
    .skipidle  (skipidle  ),
    .rx_data   (rx_data   ),
    .rx_vld    (rx_vld    ),
    .key_down  (key_down  ),
    .usedw     (usedw     ),
    .trans_done(trans_done),
    .rd_data   (rd_data   ),
    .rw_flag   (rw_flag_wr),
    .wr_data   (wr_data_wr)
);

endmodule